package com.mh.system.service.impl;

import com.mh.common.constant.Constants;
import com.mh.common.core.exception.CustomException;
import com.mh.common.utils.RedisCache;
import com.mh.common.utils.UserConstants;
import com.mh.system.domain.SysDictData;
import com.mh.system.domain.SysDictType;
import com.mh.system.mapper.SysDictDataMapper;
import com.mh.system.mapper.SysDictTypeMapper;
import com.mh.system.service.SysDictTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;

@Service
public class SysDictTypeServiceImpl implements SysDictTypeService {

    @Autowired
    private SysDictTypeMapper dictTypeMapper;

    @Autowired
    private SysDictDataMapper dictDataMapper;

    @Autowired
    private RedisCache redisCache;

    /** JAVAEE注解 @PostConstruct, 也适用于Spring
     *  Spring Bean加载后,Spring会找有此注解的方法自动执行, 常用于执行初始化操作
     */
    @PostConstruct
    public void init() {
        //获取字典类型数据
        //1. 获取type表的全部信息
        List<SysDictType> typeList = dictTypeMapper.selectDictTypeAll();
        for (SysDictType typeOne : typeList) {
            //2. 根据type对象中获取的type,获取type对应的data表的信息
            List<SysDictData> dataList = dictDataMapper.selectDictDataByType(typeOne.getDictType());
            //3. 获取到的data信息缓存到redis中(key:调用dataRedisKey(),传入每个type表元素的type)
            //type表中的一个type(唯一)对应data表中的多条数据-->type为key,data的多条数据为value
            redisCache.setCacheObject(dataRedisKey(typeOne.getDictType()),dataList);
        }
    }
    //data数据存储的redisKey抽取为一个方法
    private String dataRedisKey(String dictType) {
        //public static final String SYS_DICT_KEY = "sys_dict:"
        return Constants.SYS_DICT_KEY + dictType;
    }

    @Override
    public List<SysDictType> selectDictTypeList(SysDictType dictType) {
        return dictTypeMapper.selectDictTypeList(dictType);
    }

    @Override
    public List<SysDictType> selectDictTypeAll() {
        return dictTypeMapper.selectDictTypeAll();
    }

    //根据字典类型查询信息
    @Override
    public List<SysDictData> selectDictDataByType(String dictType) {
        //1. 先从Redis缓存中获取
        List<SysDictData> dictDataRedis = redisCache.getCacheObject(dataRedisKey(dictType));
        if( ! CollectionUtils.isEmpty(dictDataRedis) ){
            return dictDataRedis;
        }
        //2. Redis中没有的话,从数据库查询
        List<SysDictData> dictDataList = dictDataMapper.selectDictDataByType(dictType);
        if( ! CollectionUtils.isEmpty(dictDataList) ){
            //先缓存: 数据库查询结果缓存到Redis中,RedisKey调用公共方法
            redisCache.setCacheObject(dataRedisKey(dictType),dictDataList);
            //后返回
            return dictDataList;
        }
        return null;
    }

    @Override
    public SysDictType selectDictTypeById(Long dictId) {
        return dictTypeMapper.selectDictTypeById(dictId);
    }

    @Override
    public SysDictType selectDictTypeByType(String dictType) {

        return dictTypeMapper.selectDictTypeByType(dictType);
    }

    @Override
    public int deleteDictTypeByIds(Long[] dictIds) {
        //传入的id数组遍历
        for (Long dictId : dictIds) {
            //通过id获取,对应的每个type对象
            SysDictType dictTypeOne = dictTypeMapper.selectDictTypeById(dictId);
            //通过type对象的type,去data表查询,是否有该type的数据-->有返回个数,没有返回0
            int count = dictDataMapper.countDictDataByType(dictTypeOne.getDictType());
            //此方法要删除type表的type,所以删除之前看data表中是否有此type的,有的话不能删除
            //data表依赖type表
            if (count > 0) {
                throw new CustomException(500,"该类型还有其他数据,不可删除");
            }
        }
        //如果返回0, 表示data表中没有此类型,type表中删除也可以 --> 返回影响行数(删除行数)
        int row = dictTypeMapper.deleteDictTypeByIds(dictIds);
        //删除成功返回大于0的数, Redis缓存也要删除
        if (row > 0) {
            redisClear();
        }
        return row; //返回删除行数
    }
    //删除Redis缓存
    private void redisClear(){
        //前缀为"sys_dict:"的全部删除,不判断是什么类型,因此只删除A类型也是只要调用此方法就前缀一样全部删除
                Collection<String> keys = redisCache.keys(Constants.SYS_DICT_KEY + "*");
        redisCache.deleteObject(keys);
    }

    //新增数据
    @Override
    public int insertDictType(SysDictType dictType) {
        int row = dictTypeMapper.insertDictType(dictType);
        //数据有变化就清空redis缓存
        if (row > 0) {
            redisClear();
        }
        return row;
    }

    //修改字典类型信息-->修改type表,对应的data表的type也要更新
    @Override
    @Transactional //执行多条SQL,事务控制,要么都成功要么都失败
    public int updateDictType(SysDictType dictType) { //传入要修改成的对象

        //传入对象中id是原来的id, 新id的话是新增
        //type的id传入到data的mapper里,查询出原来data的对象
        SysDictType oldDict = dictTypeMapper.selectDictTypeById(dictType.getDictId());
        //调用data的mapper, 修改data的type
        //传入原来的type(就是上面查到到对象中获取) & 新的type(形参传入的中获取)
        dictDataMapper.updateDictDataType(oldDict.getDictType(),dictType.getDictType());

        //修改type的type
        int row = dictTypeMapper.updateDictType(dictType);
        //修改成功就清空redis缓存
        if (row > 0) {
            redisClear();
        }
        return row;
    }

    //校验字典类型是否唯一
    @Override
    public String checkDictTypeUnique(SysDictType dictType) {

        SysDictType exist = dictTypeMapper.checkDictTypeUnique(dictType.getDictType());
        //查询结果非空, 表示不是唯一的, 不可用同样的type
        if ( exist != null ){
            //type已存在返回1: public final static String NOT_UNIQUE = "1"
            return UserConstants.NOT_UNIQUE;
        }
        //type不存在返回0: public final static String UNIQUE = "0"
        return UserConstants.UNIQUE;
    }

    //清空缓存: 前端有清空缓存的选项,点击就是清空redis缓存
    @Override
    public void clearCache() {
        redisClear();
    }
}
